package cn.lu.project.generate.service;

import cn.lu.project.generate.entity.GenerateProperties;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.sun.javafx.PlatformUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: easycode
 * @description: 构建Java文件
 * @author: zhlu
 * @create: 2020-04-07 16:29
 * @Introduction(说明背景故事)
 **/
@Slf4j
public class BuildJavaProject {

    private static final String DB_URL = "jdbc:mysql://%s:3306/%s?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";

    public static void build(GenerateProperties properties) {
        log.info("------开始构建Java项目------");
        String path = properties.getExportSqlDir();
        if (StringUtils.isBlank(path)) {
            throw new RuntimeException("请配置输出路径");
        }

        if (properties.getDataSource() == null) {
            throw new RuntimeException("请配置DataSource");
        }

        String filePath = path + properties.getBuildConf().getModularName() +"/"+ properties.getBuildConf().getSrcMainJava();
        String resourcesPath = path + properties.getBuildConf().getModularName() +"/"+ properties.getBuildConf().getResources();
        if (PlatformUtil.isWindows()) {
            filePath = filePath.replaceAll("/+|\\\\+", "\\\\");
            resourcesPath = resourcesPath.replaceAll("/+|\\\\+", "\\\\");
        } else {
            filePath = filePath.replaceAll("/+|\\\\+", "/");
            resourcesPath = resourcesPath.replaceAll("/+|\\\\+", "/");
        }

        //第一步 全局配置
        GlobalConfig config = new GlobalConfig()
                //开启 ActiveRecord 模式
                .setActiveRecord(false)
                //生成文件的输出目录 导出路径
                .setOutputDir(filePath)
                //时间类型对应策略
                .setDateType(DateType.ONLY_DATE)
                //开启 baseColumnList
                .setBaseColumnList(true)
                //开启 swagger2 模式
                .setSwagger2(true)
                //开启 BaseResultMap
                .setBaseResultMap(true)
                //是否打开输出目录
                .setOpen(false)
                //是否覆盖已有文件
                .setFileOverride(true)
                //作者
                .setAuthor(properties.getBuildConf().getAuthor())
                //是否打开输出目录
                .setOpen(false)
                //实体命名方式
                .setEntityName("%sEntity")
                //mapper 命名方式
                .setMapperName("%sMapper")
                //Mapper xml 命名方式
                .setXmlName("%sMapper")
                //service 命名方式
                .setServiceName("%sService")
                //serviceImplName
                .setServiceImplName("%sServiceImpl")
                //controller 命名方式
                .setControllerName("%sController");


        //第二步 数据源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig
                //数据库类型  必须
                .setDbType(DbType.MYSQL)
                //驱动连接的URL
                .setUrl(String.format(DB_URL, properties.getDataSource().getHost(), properties.getDataSource().getDatabase()))
                //数据库连接用户名
                .setUsername(properties.getDataSource().getUser())
                //数据库连接密码
                .setPassword(properties.getDataSource().getPassword())
                //驱动名称
                .setDriverName(properties.getDataSource().getDriverName());


        //第三步 包配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig
                //路径配置信息
                .setParent(properties.getBuildConf().getPackageName())
                //Mapper包名
                .setMapper("dao")
                //Mapper XML包名
                .setXml("mapper")
                //Service包名
                .setService("service")
                //Service Impl包名
                .setServiceImpl("service.impl")
                //Controller包名
                .setController("controller")
                //Entity包名
                .setEntity("entity");

        //第四部 数据库表配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig
                //数据库表映射到实体的命名策略
                .setNaming(NamingStrategy.underline_to_camel)
                //数据库表字段映射到实体的命名策略, 未指定按照 naming 执行
                .setColumnNaming(NamingStrategy.underline_to_camel)
                //修改替换成你需要的表名，多个表名传数组
                .setInclude()
                //生成 @RestController 控制器
                .setRestControllerStyle(properties.getBuildConf().isRestControllerStyle())
                //【实体】是否为构建者模型（默认 false）
                .setEntityBuilderModel(true)
                //驼峰转连字符
                .setControllerMappingHyphenStyle(true)
                //是否生成实体时，生成字段注解
                .entityTableFieldAnnotationEnable(true)
                //表前缀
                .setTablePrefix(properties.getDataSource().getTablePrefix())
                //是否大写命名
                .setCapitalMode(true)
                //是否为lombok模型
                .setEntityLombokModel(true)
                .setDbColumnUnderline(true)
                //需要忽略的表名
                .setExclude(properties.getBuildConf().getExcludeTable().split(","))
                ;

        //第五步 自定义配置
        InjectionConfig injectionConfig=getInjectionConfig(properties,resourcesPath);


        //第六步 添加模板引擎
        TemplateConfig templateConfig=getTemplateConfig();


        // 代码生成器
        new AutoGenerator().setGlobalConfig(config)
                .setDataSource(dataSourceConfig)
                .setStrategy(strategyConfig)
                .setPackageInfo(packageConfig)
                .setCfg(injectionConfig)
                .setTemplate(templateConfig)
                .execute();
        log.info("------构建Java项目完成------");
    }


    private static String getDateTime() {
        LocalDateTime localDate = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return localDate.format(formatter);
    }

    /**
     * Description:自定义配置
     * @author zhlu
     * @date 2020/4/10 4:44 下午
     * @param properties
     * @param filePath
     * @return com.baomidou.mybatisplus.generator.InjectionConfig
     */
    private static InjectionConfig getInjectionConfig(GenerateProperties properties,String filePath) {
        return new InjectionConfig() {
            @Override
            public void initMap() {
                Map map = new HashMap();
                map.put("moduleName", properties.getBuildConf().getModularName());
                map.put("dateTime", getDateTime());
                setMap(map);
                List<FileOutConfig> fileOutConfigList = new ArrayList<FileOutConfig>();

                // 如果模板引擎是 freemarker
//                String templatePath = "/templates/mapper.xml.ftl";
                // 如果模板引擎是 velocity
                 String templatePath = "/templates/mapper.xml.vm";

                // 自定义配置会被优先输出
                fileOutConfigList.add(new FileOutConfig(templatePath) {
                    @Override
                    public String outputFile(TableInfo tableInfo) {
                        log.info("路径：{}",filePath);
                        // 自定义输出文件名，如果entity设置了前后缀，此次注意xml的名称也会跟着发生变化
                        return filePath + tableInfo.getEntityName() + "Mapper.xml";
                    }
                });
                setFileOutConfigList(fileOutConfigList);
            }
        };
    }

    /**
     * Description:模板引擎
     * @author zhlu
     * @date 2020/4/8 4:16 下午
     * @param
     * @return com.baomidou.mybatisplus.generator.config.TemplateConfig
     */
    private static TemplateConfig getTemplateConfig() {
        return new TemplateConfig()
                .setController("/templates-generator/controller.java.vm")
                .setService("/templates-generator/service.java.vm")
                .setServiceImpl("/templates-generator/serviceImpl.java.vm")
                .setEntity("/templates-generator/entity.java.vm")
                .setMapper("/templates-generator/mapper.java.vm")
                .setXml("/templates-generator/mapper.xml.vm");
    }
}
